home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / program / cpp112.zoo / src / define.c < prev    next >
C/C++ Source or Header  |  1994-07-06  |  6KB  |  246 lines

  1.  
  2. /*---------------------------------------------------------------------*\
  3. |                                    |
  4. | CPP -- a stand-alone C preprocessor                    |
  5. | Copyright (c) 1993 Hacker Ltd.        Author: Scott Bigham    |
  6. |                                    |
  7. | Permission is granted to anyone to use this software for any purpose    |
  8. | on any computer system, and to redistribute it freely, with the    |
  9. | following restrictions:                        |
  10. | - No charge may be made other than reasonable charges for repro-    |
  11. |     duction.                                |
  12. | - Modified versions must be clearly marked as such.            |
  13. | - The author is not responsible for any harmful consequences of    |
  14. |     using this software, even if they result from defects therein.    |
  15. |                                    |
  16. | define.c -- handle #define and #undef directives            |
  17. \*---------------------------------------------------------------------*/
  18.  
  19. #include <string.h>
  20. #include "global.h"
  21.  
  22. /*
  23.    get_parms() -- return a list of the formal parameters in a macro
  24.    definition.  Return the number of parameters in |*n|.
  25. */
  26. static TokenP get_parms(n)
  27.   register int *n;
  28. {
  29.   Token phead;
  30.   register TokenP T, parms = &phead;
  31.  
  32.   *n = 0;
  33.   phead.next = NULL;
  34.   for (;;) {
  35.     T = token();
  36.     if (T->type == EOL) {
  37.       free_token(T);
  38.       goto oops;
  39.     }
  40.     if (T->type == RPAREN) {
  41.       free_token(T);
  42.       if (*n == 0)
  43.     return NULL;
  44.       goto oops;
  45.     }
  46.     if (T->type != ID) {
  47.       free_token(T);
  48.       goto oops;
  49.     }
  50.     parms = parms->next = T;
  51.     (*n)++;
  52.     T = token();
  53.     switch (T->type) {
  54.     case COMMA:
  55.       free_token(T);
  56.       continue;
  57.     case RPAREN:
  58.       free_token(T);
  59.       return phead.next;
  60.     default:
  61.       free_token(T);
  62.       goto oops;
  63.     }
  64.   }
  65. oops:
  66.   error("syntax error in macro definition");
  67.   if (parms)
  68.     free_tlist(parms);
  69.   *n = -1;
  70.   return NULL;
  71. }
  72.  
  73. /*
  74.    macro_eq() -- determine if macro bodies |M1| and |M2| are equal, modulo
  75.    whitespace.  Currently experimental.
  76. */
  77. int macro_eq(M1, M2)
  78.   Macro *M1, *M2;
  79. {
  80.   register TokenP h1, h2;
  81.   if (M1->flags != M2->flags || M1->nargs != M2->nargs)
  82.     return 0;
  83.   for (h1 = M1->argnames, h2 = M2->argnames;
  84.        h1 && h2;
  85.        h1 = h1->next, h2 = h2->next)
  86.     if (!streq(token_txt(h1), token_txt(h2)))
  87.       return 0;
  88.   for (h1 = M1->m_text, h2 = M2->m_text;
  89.        h1 && h2;
  90.        h1 = h1->next, h2 = h2->next)
  91.     if (h1->type != h2->type &&
  92.         h1->subtype != h2->subtype &&
  93.         h1->hashval != h2->hashval &&
  94.         !streq(token_txt(h1), token_txt(h2)) &&
  95.         (h1->flags & ~BLUEPAINT) != (h2->flags & ~BLUEPAINT))
  96.       return 0;
  97.   return 1;
  98. }
  99.  
  100. /*
  101.    is_parm() -- determine if Token |T| is one of the formal parameters of the
  102.    macro.  Return the "index" into the list of parameters, or -1 if there is
  103.    no match
  104. */
  105. static int is_parm(T, parms)
  106.   register TokenP T, parms;
  107. {
  108.   int i;
  109.   register TokenP t;
  110.  
  111.   if (parms == NULL)
  112.     return -1;
  113.   for (i = 0, t = parms; t; i++, t = t->next) {
  114.     if (streq(token_txt(T), token_txt(t))) {
  115.       return i;
  116.     }
  117.   }
  118.   return -1;
  119. }
  120.  
  121. /* do_define() -- handle a #define directive */
  122. void do_define()
  123. {
  124.   TokenP K, L;
  125.   register TokenP T, pT;
  126.   register Macro *M, *M1;
  127.   int i;
  128.   static Token head;
  129.  
  130.   _tokenize_line();
  131.   K = token();
  132.   if (K->type != ID) {
  133.     error("argument \"%s\" to #define is not an identifier",
  134.       token_txt(K));
  135.     free_token(K);
  136.     return;
  137.   }
  138.   M = mk_Macro();
  139.  
  140.   T = token();
  141.   if (strlen(token_ws(T)) == 0 && T->type == LPAREN) {
  142.     /* a macro with arguments -- get the formal parameters */
  143.     free_token(T);
  144.     M->flags |= HASARGS;
  145.     M->argnames = get_parms(&M->nargs);
  146.     if (M->nargs < 0) {
  147.       free_Macro(M);
  148.       return;
  149.     }
  150.   } else {
  151.     M->nargs = 0;
  152.     M->argnames = NULL;
  153.     push_tlist(T);
  154.   }
  155.   L = &head;
  156.   head.next = NULL;
  157.   for (;;) {
  158.     T = token();
  159.     if (T->type == EOL) {
  160.       free_token(T);
  161.       break;
  162.     }
  163.     switch (T->type) {
  164.     case POUND:
  165.       free_token(T);
  166.       T = token();
  167.       if ((i = is_parm(T, M->argnames)) < 0) {
  168.     error("# not followed by macro parameter");
  169.     push_tlist(T);
  170.     break;
  171.       }
  172.       T->type = MACRO_ARG;
  173.       T->flags |= STRINGIZE_ME;
  174.       T->val = i;
  175.       L = L->next = T;
  176.       break;
  177.     case TOK_CAT:
  178.       free_token(T);
  179.       T = token();
  180.       if (L == &head || T->type == EOL) {
  181.     if (L == &head)
  182.       error("## at beginning of macro body");
  183.     if (T->type == EOL)
  184.       error("## at end of macro body");
  185.     break;
  186.       }
  187.       L->flags |= CONCAT_NEXT;
  188.       push_tlist(T);
  189.       break;
  190.     case ID:
  191.       if ((i = is_parm(T, M->argnames)) >= 0) {
  192.     T->type = MACRO_ARG;
  193.     T->val = i;
  194.       }
  195.       L = L->next = T;
  196.       break;
  197.     default:
  198.       L = L->next = T;
  199.       break;
  200.     }
  201.   }
  202.   /* remove leading space from the resulting sequence */
  203.   T = head.next;
  204.   if (T)
  205.     clear_ws(T);
  206.   M->m_text = head.next;
  207.  
  208.   /*
  209.      As per the Standard, a macro can only be re-#define'd with an identical
  210.      body, modulo whitespace.
  211.   */
  212.   if ((M1 = lookup(token_txt(K), K->hashval)) && !macro_eq(M, M1)) {
  213.     warning("non-identical redefine of \"%s\"", token_txt(K));
  214.     free_Macro(M);
  215.   } else {
  216.     hash_add(token_txt(K), K->hashval, M);
  217.   }
  218.   free_token(K);
  219. }
  220.  
  221. /* do_undefine() -- handle an #undef directive */
  222. void do_undefine()
  223. {
  224.   register Macro *M;
  225.   register TokenP T;
  226.  
  227.   T = _one_token();
  228.   if (T->type != ID) {
  229.     if (T->type == EOL)
  230.       error("missing argument to #undef");
  231.     else
  232.       error("argument \"%s\" to #undef is not an identifier",
  233.         token_txt(T));
  234.     free_token(T);
  235.     return;
  236.   }
  237.   M = lookup(token_txt(T), T->hashval);
  238.   if (M && !(M->flags & MAGIC))
  239.     hash_remove(token_txt(T), T->hashval);
  240.   free_token(T);
  241.   T = _one_token();
  242.   if (T->type != EOL)
  243.     warning("garbage after #undef");
  244.   free_token(T);
  245. }
  246.